[#851] Port Linux/Windows instrument-driver menu items to Qt - #881
Merged
Conversation
…rsion to 3.10.0.dev49 Add the 4 platform-conditional Instrument-submenu items that were missing from the Qt MainWindow: Linux udev-rules config install/uninstall and Windows driver install/uninstall, gated the same way wx gates them (`sys.platform`/`TEST` flag), including their confirmation dialogs and `authenticate()`-driven elevated-install flow. Also fix `Worker.authenticate()` unconditionally constructing a `BetterWindowDisabler()`, which touches `wx.GetTopLevelWindows()` and crashes the process natively on Linux/GTK when no `wx.App` is running (the new Linux code path can hit this under Qt-only operation); guard it with `wx.GetApp() is not None`.
Every "instrument connected" / "measurement taken" / startup chime (`worker.py`'s measurement/commit sounds, `display_cal.py`'s startup sound, `ui/startup.py`'s `play_startup_sound()`, the untethered window, ...) goes through `audio.Sound(path).safe_play()`. All of those call sites reference it as `audio.Sound(...)`, so replacing the class attribute with the module's own no-op `DummySound` in `conftest.py`, before any other DisplayCAL module runs, silences beep.wav/ camera_shutter.wav/intro_new.wav for the whole test session instead of needing a per-file monkeypatch.
…touse fixture test_confirm_bpc_choice_turn_on_accept_persists_bpc drives the real _confirm_black_point_correction_choice() "accept" path, which persists calibration.black_point_correction = 1.0, and never restores it. Left leaked, a later test's freshly-constructed window initializes its black-point-correction control from that value, satisfying one of measurement_mode_ctrl_handler()'s guards for showing the (here unmocked) BPC choice QMessageBox, which then blocks forever on a headless CI runner. Same "config leak wakes a real modal" trap the fixture already guards against for 3 other keys, just missing this one; caught via a real hang in test_measurement_mode_ctrl_populates_and_persists on Linux + Python 3.12 CI (PR #881, run 29646328469).
…atform sys.platform spoof crash test_instrument_menu_matches_wx_xrc_order, test_instrument_conf_and_ driver_actions_absent_on_macos_by_default, and test_update_instrument_ conf_menu_state_noop_without_action all asserted "no platform-conditional instrument items" using the shared `window` fixture, which builds against whatever the real CI host's sys.platform actually is. That only holds on macOS; on real Linux/Windows CI hosts the #851 items now legitimately exist, and both failed for real (PR #881 run 29646328469). Pinning them to "darwin" via `monkeypatch.setattr(mw.sys, "platform", ...)` + `mw.MainWindow()` (the pattern the existing test_instrument_conf_actions_present_on_linux already used) isn't safe either: `mw.sys` is the real global `sys` module, so the patch also reaches the `Worker()` -> `ThreadAbort()` -> `mp.Event()` call `MainWindow.__init__` makes internally, and CPython's own `multiprocessing` resource-tracker dispatches its spawn path off that same real `sys.platform`. Spoofing "linux"/"darwin" while the real host is Windows makes it try to `import _posixsubprocess`, which doesn't exist there, crashing the whole worker instead of failing the assertion (seen for real on Windows CI, same run). Added `_build_window_with_platform()`: construct and enumerate the `Worker` first (under the real, unspoofed platform), *then* spoof `sys.platform` and hand the already-built worker to `MainWindow(worker=...)`, so `__init__` adopts it instead of constructing (and spoof-crashing on) its own. All 4 platform-spoofing tests in this section now go through it.
…own sys reference The previous fix (construct Worker() before spoofing mw.sys.platform) only patched over one specific crash. mw.sys is the real, single global sys module, so monkeypatch.setattr(mw.sys, "platform", ...) doesn't just affect _build_tools_menu()'s own gate -- it reaches every other module's sys.platform reads for the rest of the test too. Confirmed a second, different crash from the same root cause on Linux CI: DisplayCAL.config only imports LIBRARY/LIBRARY_HOME at module-import time when the *real* host is "darwin" (config.py:26-37), so spoofing "darwin" on a real Linux host makes colorimeter_correction.py's data-file lookup raise AttributeError: module 'DisplayCAL.config' has no attribute 'LIBRARY' the moment MainWindow build reaches the CCXX catalog (PR #881, run 29647026132). Replace the spoof mechanism: instead of mutating the shared sys module, replace the *name* `sys` inside main_window's own module namespace with a _FakeSysModule that overrides only `.platform` and delegates every other attribute (argv, exit, getwindowsversion) to the real sys module. This confines the spoof to exactly main_window.py's own platform checks, so config.py, colorimeter_correction.py, and CPython's own multiprocessing dispatch all keep seeing the real, unmodified sys.platform. Simpler too: no longer needs to pre-construct and adopt a Worker to dodge the mp.Event() crash, since the real sys module (and therefore multiprocessing's dispatch) is never touched.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
MainWindow(issue [Qt] Linux/Windows instrument-driver menu items missing (install/uninstall udev rules & drivers) #851): Linux udev-rules configuration file install/uninstall, and Windows instrument driver install/uninstall, gated the same way wx gates them (sys.platform/TESTflag), including their confirmation dialogs and theauthenticate()-driven elevated-install flow.Worker.authenticate()unconditionally constructing aBetterWindowDisabler(), which toucheswx.GetTopLevelWindows()and crashes natively on Linux/GTK when nowx.Appis running, a path the new Linux menu items can now reach under Qt-only operation.tests/conftest.py), sobeep.wav/camera_shutter.wav/intro_new.wavno longer play during test runs.Test plan
pytest tests/test_ui_main_window.py(23 new tests covering menu presence/absence, dialog flows, and both handlers) — 535 passedpytest tests/ -n auto) — 2511 passed, 21 skippedMainWindow()and confirmed the udev-conf menu actions appear/behave correctly